// Common/Lang.cpp

#include "StdAfx.h"

#include "Lang.h"
#include "Common/String/TextConfig.h"

#include "Common/Stream/FileIO.h"
#include "Common/String/UTFConvert.h"
#include "Common/MyFixes.h"
#include "Common/Defs.h"

#include <algorithm>

namespace Common
{
namespace Lang
{

static bool HexStringToNumber(const CString &s, UINT32 &value)
{
  value = 0;
  if (s.IsEmpty())
    return false;
  for (int i = 0; i < s.GetLength(); i++)
  {
    TCHAR c = s[i];
    int a;
    if (c >= _T('0') && c <= _T('9'))
      a = c - _T('0');
    else if (c >= _T('A') && c <= _T('F'))
      a = 10 + c - _T('A');
    else if (c >= _T('a') && c <= _T('f'))
      a = 10 + c - _T('a');
    else
      return false;
    value *= 0x10;
    value += a;
  }
  return true;
}


static bool WaitNextLine(const CStringA &s, int &pos)
{
  for (; pos < s.GetLength(); pos++)
    if (s[pos] == 0x0A)
      return true;
  return false;
}

//static int CompareLangItems(void *const *elem1, void *const *elem2, void *)
bool CompareLangItems(const CLangPair &langPair1, const CLangPair &langPair2)
{
  //const CLangPair &langPair1 = *(*((const CLangPair **)elem1));
  //const CLangPair &langPair2 = *(*((const CLangPair **)elem2));
  return 0 > simpleCompare(langPair1.Value, langPair2.Value);
}

bool CLang::Open(LPCTSTR fileName)
{
  _langPairs.clear();
  Common::IO::CInFile file;
  if (!file.Open(fileName))
    return false;
  UINT64 length;
  if (!file.GetLength(length))
    return false;
  if (length > (1 << 20))
    return false;
  CStringA s;
  char *p = s.GetBuffer((int)length + 1);
  UINT32 processed;
  if (!file.Read(p, (UINT32)length, processed))
    return false;
  p[(UINT32)length] = 0;
  s.ReleaseBuffer();
  file.Close();
  int pos = 0;
  if (s.GetLength() >= 3)
  {
    if (BYTE(s[0]) == 0xEF && BYTE(s[1]) == 0xBB && BYTE(s[2]) == 0xBF)
      pos += 3;
  }

  /////////////////////
  // read header

  CStringA stringID = ";!@Lang@!UTF-8!";
  if (s.Mid(pos, stringID.GetLength()) != stringID)
    return false;
  pos += stringID.GetLength();
  
  if (!WaitNextLine(s, pos))
    return false;

  std::vector<String::CTextConfigPair> pairs;
  if (!GetTextConfig(s.Mid(pos), pairs))
    return false;

  _langPairs.reserve(_langPairs.size());
  std::vector<String::CTextConfigPair>::size_type i(0);
  for (; i < pairs.size(); i++)
  {
    String::CTextConfigPair textConfigPair = pairs[i];
    CLangPair langPair;
    if (!HexStringToNumber(textConfigPair.ID, langPair.Value))
      return false;
    langPair.String = textConfigPair.String;
	_langPairs.push_back(langPair);
  }
  std::sort(_langPairs.begin(), _langPairs.end() , CompareLangItems);
  return true;
}

int CLang::FindItem(UINT32 value) const
{
  size_t left = 0, right = _langPairs.size();
  while (left != right)
  {
    UINT32 mid = (left + right) / 2;
    UINT32 midValue = _langPairs[mid].Value;
    if (value == midValue)
      return mid;
    if (value < midValue)
      right = mid;
    else
      left = mid + 1;
  }
  return -1;
}

bool CLang::GetMessage(UINT32 value, CString &message) const
{
  int index =  FindItem(value);
  if (index < 0)
    return false;
  message = _langPairs[index].String;
  return true;
}

}
}